package cn.sciento.boot.transfer.api.dto;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import cn.sciento.core.exception.CommonException;
import org.apache.ibatis.mapping.SqlCommandType;
import cn.sciento.boot.data.change.dto.ChangeData;
import cn.sciento.boot.transfer.infra.feign.HdttRemoteService;
import cn.sciento.core.base.BaseConstants;

public class ProcessMsgDTO {
  private String keyField;
  
  private String table;
  
  private String action;
  
  private String type;
  
  private Integer tlFlag;
  
  private Integer tenantFlag;
  
  private Long tenantId;
  
  private Long eventId;
  
  private String sourceService;
  
  private Date produceTime;
  
  private List<Map<String, Object>> data;
  
  public static List<ProcessMsgDTO> buildProcessMsgList(HdttRemoteService hdttRemoteService, List<ChangeData> changeDataList, String serviceName, Integer tenantFlag) {
    List<ProcessMsgDTO> processMsgList = new ArrayList<>();
    ChangeData changeData = changeDataList.get(0);
    List<Map<String, Object>> dataMapList = new ArrayList<>();
    if (changeData.getAction() == SqlCommandType.DELETE) {
      changeDataList.forEach(item -> dataMapList.add(item.getBeforeEntityMap()));
    } else {
      changeDataList.forEach(item -> dataMapList.add(item.getAfterEntityMap()));
    } 
    if (BaseConstants.Flag.YES.equals(tenantFlag)) {
      Map<Long, List<Map<String, Object>>> groups = dataMapList.stream().collect(Collectors.groupingBy(item -> (Long)item.get("tenantId")));
      for (Map.Entry<Long, List<Map<String, Object>>> entry : groups.entrySet()) {
        Long tenantId = entry.getKey();
        List<Map<String, Object>> value = entry.getValue();
        ProcessMsgDTO processMsgDTO = buildProcessMsg(hdttRemoteService, changeData, serviceName);
        processMsgDTO.setTenantId(tenantId);
        processMsgDTO.setTenantFlag(tenantFlag);
        processMsgDTO.setData(value);
        processMsgList.add(processMsgDTO);
      } 
    } else {
      ProcessMsgDTO processMsgDTO = buildProcessMsg(hdttRemoteService, changeData, serviceName);
      processMsgDTO.setTenantFlag(tenantFlag);
      processMsgDTO.setData(dataMapList);
      processMsgList.add(processMsgDTO);
    } 
    return processMsgList;
  }
  
  private static ProcessMsgDTO buildProcessMsg(HdttRemoteService hdttRemoteService, ChangeData changeData, String serviceName) {
    Long eventId = hdttRemoteService.getDistributionId("HDTT");
    if (null == eventId)
      throw new CommonException("create distribution Id failed");
    ProcessMsgDTO processMsg = new ProcessMsgDTO();
    processMsg.setAction(changeData.getAction().name());
    processMsg.setEventId(eventId);
    processMsg.setKeyField(changeData.getKeyField());
    processMsg.setTable(changeData.getTableName());
    processMsg.setType("DATA");
    processMsg.setSourceService(serviceName);
    processMsg.setProduceTime(new Date());
    Integer tlFlag = changeData.getTlFlag() ? BaseConstants.Flag.YES : BaseConstants.Flag.NO;
    processMsg.setTlFlag(tlFlag);
    return processMsg;
  }
  
  public String getKeyField() {
    return this.keyField;
  }
  
  public void setKeyField(String keyField) {
    this.keyField = keyField;
  }
  
  public String getTable() {
    return this.table;
  }
  
  public void setTable(String table) {
    this.table = table;
  }
  
  public String getAction() {
    return this.action;
  }
  
  public void setAction(String action) {
    this.action = action;
  }
  
  public String getType() {
    return this.type;
  }
  
  public void setType(String type) {
    this.type = type;
  }
  
  public Integer getTlFlag() {
    return this.tlFlag;
  }
  
  public void setTlFlag(Integer tlFlag) {
    this.tlFlag = tlFlag;
  }
  
  public Integer getTenantFlag() {
    return this.tenantFlag;
  }
  
  public void setTenantFlag(Integer tenantFlag) {
    this.tenantFlag = tenantFlag;
  }
  
  public Long getEventId() {
    return this.eventId;
  }
  
  public void setEventId(Long eventId) {
    this.eventId = eventId;
  }
  
  public List<Map<String, Object>> getData() {
    return this.data;
  }
  
  public void setData(List<Map<String, Object>> data) {
    this.data = data;
  }
  
  public String getSourceService() {
    return this.sourceService;
  }
  
  public void setSourceService(String sourceService) {
    this.sourceService = sourceService;
  }
  
  public Date getProduceTime() {
    return this.produceTime;
  }
  
  public void setProduceTime(Date produceTime) {
    this.produceTime = produceTime;
  }
  
  public Long getTenantId() {
    return this.tenantId;
  }
  
  public void setTenantId(Long tenantId) {
    this.tenantId = tenantId;
  }
}
